#include "random-students.h"
RandomStudent::RandomStudent(QWidget *parent) : QMainWindow(parent)
{
	createUI();
	QFile listFile(studentsFilePath);
	if (listFile.open(QFile::ReadOnly)) {
		QTextStream in(&listFile);
		int lineCount = 0;
		while (!in.atEnd())
			if (!in.readLine().trimmed().isEmpty()) lineCount++;
		listFile.close();
		if (lineCount > 127) {
			QMessageBox *msgBox = new QMessageBox(QMessageBox::Critical, "错误", "学生名单超过最大限制127人！\n请删减名单后重新运行程序。", QMessageBox::Close, this);
			msgBox->setAttribute(Qt::WA_DeleteOnClose);
			connect(msgBox, &QMessageBox::finished, [](int result) { qApp->quit(); });
			msgBox->show();
			return;
		}
		studentCount = lineCount;
		studentNames = new QString[studentCount];
		studentIdQueue = new char[studentCount + 1];
		listFile.open(QFile::ReadOnly);
		QTextStream contentReader(&listFile);
		for (int i = 0; i < studentCount;) {
			QString line = contentReader.readLine().trimmed();
			if (!line.isEmpty()) studentNames[i++] = line;
		}
		listFile.close();
	} else {
		studentCount = 52;
		studentNames = new QString[studentCount];
		studentIdQueue = new char[studentCount + 1];
		for (short i = 0; i < studentCount; i++) studentNames[i] = QString::number(i + 1);
	}
	spinBox->setMaximum(studentCount);
	horizontalSlider->setMaximum(studentCount);
	if (QFile::exists(studentsSessionFilePath)) {
		QFile file(studentsSessionFilePath);
		if (file.open(QFile::ReadOnly)) {
			QByteArray data = file.readAll();
			if (data.size() != studentCount + 1) {
				file.close();
				QFile::remove(studentsSessionFilePath);
				QMessageBox::warning(this, "错误", "会话文件大小异常，已删除");
				goto INIT_SESSION;
			}
			char *m = data.data();
			bool dataValid = true;
			for (int i = 0; i < studentCount; i++) {
				if (m[i] < 0 || m[i] >= studentCount) {
					dataValid = false;
					break;
				}
			}
			if (!dataValid) {
				QFile::remove(studentsSessionFilePath);
				QMessageBox::warning(this, "错误", "会话数据异常，已删除");
				goto INIT_SESSION;
			}
			memcpy(studentIdQueue, m, studentCount);
			currentStudentIndex = m[studentCount];
		}
	} else {
	INIT_SESSION:
		startRandomButton->setText("点击随机点名");
		for (int i = 0; i < studentCount; i++) studentIdQueue[i] = i;
		RandomlyScrambled(0, studentCount);
	}
	watcher->addPath(studentsFilePath);
	connect(watcher, &QFileSystemWatcher::fileChanged, this, &RandomStudent::onStudentListChanged);
	connect(timer, SIGNAL(timeout()), this, SLOT(showStudents()));
	connect(chose, SIGNAL(timeout()), this, SLOT(selectNextStudent()));
#ifdef WIN32
	keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);
	QTimer *checkTopMostTimer = new QTimer(this);
	QObject::connect(checkTopMostTimer, &QTimer::timeout, [this]() {
		if (!this->isHidden()) SetWindowPos(reinterpret_cast<HWND>(winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
	});
	checkTopMostTimer->start(1000);
#endif
}
RandomStudent::~RandomStudent()
{
	delete[] studentNames;
	delete[] studentIdQueue;
#ifdef WIN32
	UnhookWindowsHookEx(keyboardHook);
#endif
}
void RandomStudent::createUI()
{
	setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
	setWindowOpacity(0.9);
	setWindowTitle("随机点名");
	setWindowIcon(QIcon(":/img/random_call.svg"));
	setStyleSheet(R"(*{font-size: 27pt;}QPushButton{border-radius: 17px;background-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(55, 131, 255, 255), stop:1 rgba(165, 191, 214, 255))}QPushButton:hover{background-color: #00ff00;})");
	QWidget *centralWidget = new QWidget(this);
	QGridLayout *layout = new QGridLayout(centralWidget);
	spinBox = new QSpinBox(centralWidget);
	horizontalSlider = new QSlider(Qt::Horizontal, centralWidget);
	startRandomButton = new QPushButton("点击随机点名", centralWidget);
	historyButton = new QPushButton("点名历史", centralWidget);
	speakButton = new QPushButton("语音", centralWidget);
	spinBox->setAlignment(Qt::AlignCenter);
	spinBox->setSuffix("人");
	spinBox->setMinimum(1);
	horizontalSlider->setMinimum(1);
	layout->addWidget(spinBox, 0, 0, 1, 2);
	layout->addWidget(horizontalSlider, 1, 0, 1, 2);
	layout->addWidget(historyButton, 2, 0);
	layout->addWidget(speakButton, 2, 1);
	layout->addWidget(startRandomButton, 3, 0, 1, 2);
	layout->addWidget(new QLabel("<p style='font-size:11pt;'>可双击翻页笔`音量加`点名</p>", centralWidget), 4, 0, 1, 2);
	connect(spinBox, SIGNAL(valueChanged(int)), horizontalSlider, SLOT(setValue(int)));
	connect(horizontalSlider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
	connect(startRandomButton, &QPushButton::clicked, this, &RandomStudent::on_startRandomButton_clicked);
	connect(historyButton, &QPushButton::clicked, this, &RandomStudent::on_historyButton_clicked);
	connect(speakButton, &QPushButton::clicked, this, &RandomStudent::on_speak_clicked);
	setCentralWidget(centralWidget);
}
void RandomStudent::onStudentListChanged()
{
	if (timer->isActive()) timer->stop();
	if (chose->isActive()) chose->stop();
	QFile::remove(studentsSessionFilePath);
	QFile listFile(studentsFilePath);
	if (listFile.open(QFile::ReadOnly)) {
		QTextStream in(&listFile);
		int lineCount = 0;
		while (!in.atEnd())
			if (!in.readLine().trimmed().isEmpty()) lineCount++;
		listFile.close();
		if (lineCount > 127) {
			QMessageBox::critical(this, "错误", "学生名单超过最大限制127人！程序将退出。");
			qApp->quit();
			return;
		}
		delete[] studentNames;
		delete[] studentIdQueue;
		studentCount = lineCount;
		studentNames = new QString[studentCount];
		studentIdQueue = new char[studentCount + 1];
		listFile.open(QFile::ReadOnly);
		QTextStream contentReader(&listFile);
		for (int i = 0; i < studentCount;) {
			QString line = contentReader.readLine().trimmed();
			if (!line.isEmpty()) studentNames[i++] = line;
		}
		listFile.close();
		spinBox->setMaximum(studentCount);
		horizontalSlider->setMaximum(studentCount);
		for (int i = 0; i < studentCount; i++) studentIdQueue[i] = i;
		RandomlyScrambled(0, studentCount);
		currentStudentIndex = 0;
		startRandomButton->setText("点击随机点名");
		startRandomButton->setEnabled(true);
	}
	if (!watcher->files().contains(studentsFilePath)) watcher->addPath(studentsFilePath);
}
void RandomStudent::selectNextStudent()
{
	selectedStudentsText += studentNames[studentIdQueue[currentStudentIndex]];
	qDebug() << studentNames[studentIdQueue[currentStudentIndex++]].toUtf8().data();
	if (currentStudentIndex >= studentCount) currentStudentIndex = 0;
	if (selectedCount >= count - 1) {
		timer->stop();
		chose->stop();
		startRandomButton->setText(selectedStudentsText);
		QFile file(studentsSessionFilePath);
		while (!file.open(QFile::WriteOnly)) QMessageBox::warning(this, "随机点名", "写入下一次会话出错!");
		QDataStream out(&file);
		studentIdQueue[studentCount] = currentStudentIndex;
		out.writeRawData(studentIdQueue, studentCount + 1);
		file.close();
		QFile history(studentsHistoryFilePath);
		history.open(QFile::WriteOnly | QFile::Text | QFile::Append);
		history.write("(" + (QString::number(count) + "人)\n" + selectedStudentsText + "\n------------\n").toUtf8());
		history.close();
		repaint();
		update();
		on_speak_clicked();
		startRandomButton->setEnabled(1);
		spinBox->setEnabled(1);
		horizontalSlider->setEnabled(1);
		if (historyDialog) {
			historyDialog->disconnect();
			historyDialog->close();
			historyDialog->deleteLater();
			historyDialog = nullptr;
		}
	} else {
		selectedStudentsText += ", ";
		if (((selectedCount + 1) % 10 == 0) && (selectedCount >= 9)) selectedStudentsText += "\n";
	}
	selectedCount++;
	QRect winRect = geometry();
	if (winRect.right() > screenx + screenw) winRect.moveRight(screenx + screenw);
	if (winRect.left() < screenx) winRect.moveLeft(screenx);
	if (winRect.bottom() > screeny + screenh) winRect.moveBottom(screeny + screenh);
	if (winRect.top() < screeny) winRect.moveTop(screeny);
	if (winRect != this->geometry()) this->setGeometry(winRect);
}
void RandomStudent::showStudents() { startRandomButton->setText(selectedStudentsText + studentNames[QRandomGenerator::global()->bounded(0, studentCount)]); }
void RandomStudent::on_startRandomButton_clicked()
{
	if (!startRandomButton->isEnabled()) return;
	startRandomButton->setEnabled(0);
	spinBox->setEnabled(0);
	horizontalSlider->setEnabled(0);
	selectedStudentsText = "";
	NUM = spinBox->value();
	switch (NUM) {
	case 2:
		setWindowTitle("随机配偶");
		historyButton->setText("配偶历史");
		break;
	case 3:
		setWindowTitle("随机家庭");
		historyButton->setText("家庭历史");
		break;
	case 4:
		setWindowTitle("随机二胎");
		historyButton->setText("二胎历史");
		break;
	case 5:
		setWindowTitle("随机三胎");
		historyButton->setText("三胎历史");
		break;
	default:
		setWindowTitle("随机点名");
		historyButton->setText("点名历史");
		break;
	}
	count = NUM;
	QPropertyAnimation *shrink = new QPropertyAnimation(this, "geometry");
	QRect original = geometry();
	QRect minimized = original;
	minimized.setSize(QSize(0, 0));
	shrink->setDuration(200);
	shrink->setStartValue(geometry());
	shrink->setEndValue(minimized);
	shrink->setEasingCurve(QEasingCurve::InOutQuad);
	shrink->start(QAbstractAnimation::DeleteWhenStopped);
	RandomlyScrambled(0, currentStudentIndex);
	RandomlyScrambled(currentStudentIndex, studentCount);
	selectedCount = 0;
	timer->start(16);
	chose->start(250);
}
void RandomStudent::on_spinBox_valueChanged(int arg1) { horizontalSlider->setValue(spinBox->value()); }
void RandomStudent::on_horizontalSlider_valueChanged(int value) { spinBox->setValue(horizontalSlider->value()); }
void RandomStudent::on_historyButton_clicked()
{
	if (historyDialog) {
		historyDialog->deleteLater();
		historyDialog = nullptr;
	}
	historyDialog = new QDialog(this);
	historyDialog->setAttribute(Qt::WA_DeleteOnClose);
	connect(historyDialog, &QDialog::destroyed, [this]() { historyDialog = nullptr; });
	historyDialog->setWindowTitle("点名历史记录");
	historyDialog->setMinimumSize(800, 600);
	historyDialog->setStyleSheet("font-size: 20px;");
	QScrollArea *scrollArea = new QScrollArea(historyDialog);
	scrollArea->setWidgetResizable(true);
	scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
	scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	QScroller::grabGesture(scrollArea->viewport(), QScroller::TouchGesture);
	QWidget *contentWidget = new QWidget;
	QVBoxLayout *layout = new QVBoxLayout(contentWidget);
	QFile file(studentsHistoryFilePath);
	if (file.open(QFile::ReadOnly | QFile::Text)) {
		QTextStream in(&file);
		while (!in.atEnd()) {
			QString line = in.readLine();
			if (line.trimmed() == "------------") {
				QFrame *line = new QFrame;
				line->setFrameShape(QFrame::HLine);
				line->setStyleSheet("margin: 0; background: black;");
				layout->addWidget(line);
			} else {
				QLabel *label = new QLabel(line);
				label->setWordWrap(true);
				layout->addWidget(label);
			}
		}
		file.close();
	} else {
		QLabel *errorLabel = new QLabel("暂无历史记录, 或历史记录损坏");
		errorLabel->setAlignment(Qt::AlignCenter);
		layout->addWidget(errorLabel);
	}
	contentWidget->setLayout(layout);
	scrollArea->setWidget(contentWidget);
	QTimer::singleShot(0, [scrollArea]() {
		QScrollBar *scrollBar = scrollArea->verticalScrollBar();
		scrollBar->setValue(scrollBar->maximum());
	});
	QVBoxLayout *mainLayout = new QVBoxLayout(historyDialog);
	mainLayout->addWidget(scrollArea);
	historyDialog->setLayout(mainLayout);
	historyDialog->setAttribute(Qt::WA_DeleteOnClose);
	historyDialog->show();
}
void RandomStudent::on_speak_clicked()
{
#ifdef WIN32
	Speaker::instance().speak(selectedStudentsText);
#endif
}
#ifdef WIN32
LRESULT CALLBACK RandomStudent::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode == HC_ACTION && wParam == WM_KEYDOWN) {
		if (((KBDLLHOOKSTRUCT *) lParam)->vkCode == VK_VOLUME_UP) {
			DWORD currentTime = GetTickCount();
			static DWORD lastTime = 0;
			if (currentTime - lastTime < 300) {
				foreach (QWidget *widget, QApplication::topLevelWidgets()) {
					if (RandomStudent *window = qobject_cast<RandomStudent *>(widget)) {
						window->spinBox->setValue(1);
						window->on_startRandomButton_clicked();
					}
				}
				lastTime = 0;
			} else lastTime = currentTime;
		}
	}
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}
#endif
